using IQIGame.Onigao.Game;
using IQIGame.Onigao.GamePlay;
using System;
using System.Collections.Generic;

namespace IQIGame.Onigao.Logic
{
    public static class LgLevelEntityUtil
    {
        private static HashSet<int> _tempEntityTagOrMcids = new HashSet<int>();

        public static bool IsTag(int sign)
        {
            return sign <= ushort.MaxValue;
        }

        public static LevelHeroEntity GetClosestHero(LevelEntity entity)
        {
            float minSqrDis = int.MaxValue;
            LevelHeroEntity closestHero = null;
            foreach (LevelPlayer player in entity.region.players)
            {
                float sqrDis = (player.entity.position - entity.position).sqrMagnitude;
                if (sqrDis < minSqrDis)
                {
                    minSqrDis = sqrDis;
                    closestHero = player.entity;
                }
            }
            return closestHero;
        }

        public static LevelHeroEntity GetHeroInSight(LevelEntity entity)
        {
            LevelHeroEntity heroEntity = null;
            foreach (var player in entity.region.players)
            {
                if (player.isUndetectable)
                {
                    continue;
                }
                if (entity.IsEntityInSight(player.entity))
                {
                    heroEntity = player.entity;
                    break;
                }
            }
            return heroEntity;
        }

        /// <summary>
        /// 计算制定位置在不在矩形中间
        /// </summary>
        /// <param name="targetPos"></param>
        /// <param name="rectEntityPos"></param>
        /// <param name="rect">xy被当做center使用的矩形</param>
        /// <returns></returns>
        public static bool XYCenterRectContains(Vector3Logic targetPos, Vector3Logic rectEntityPos, RectInt rect)
        {
            return XYCenterRectContains(targetPos, rectEntityPos, rect, out _);
        }

        public static bool XYCenterRectContains(Vector3Logic targetPos, Vector3Logic rectEntityPos, RectInt rect, out int errorCode)
        {
            float physicY = (int)rectEntityPos.y;
            float curY = targetPos.y;
            //高度超出范围直接认为移动失败
            //目前是只需要判断一个二维平面，就单独特殊计算了高度，如果以后需要判断一个三维BOX，这里需要调整
            //逻辑层判断的高度比客户端更宽裕，但注意，如果是电梯这种二维平面的判断，容错范围最好不要超过200，因为我们两层楼之间的距离一般在200-300，如果超过200可能会出现问题
            if (Math.Abs(physicY - curY) > 100)
            {
                errorCode = 1;
                return false;
            }
            RectInt physicArea = CalcWorldStandardRect(rectEntityPos.x, rectEntityPos.z, rect);
            bool isInArea = physicArea.Contains((int)targetPos.x, (int)targetPos.z);
            errorCode = isInArea ? 0 : 2;
            return isInArea;
        }

        /// <summary>
        /// 获取距离targetPos最近的，在rect（以xy为center的RectInt）内的点
        /// </summary>
        /// <param name="targetPos"></param>
        /// <param name="rectEntityPos"></param>
        /// <param name="rect">以xy为center的RectInt</param>
        /// <returns></returns>
        public static Vector3Logic GetNearestPosFromXYCenterRect(Vector3Logic targetPos, Vector3Logic rectEntityPos, RectInt rect)
        {
            Vector3Logic result = targetPos;
            RectInt worldStandardArea = CalcWorldStandardRect(rectEntityPos.x, rectEntityPos.z, rect);
            if (!worldStandardArea.Contains((int)targetPos.x, (int)targetPos.z))
            {
                float nearestX = Math.Max(worldStandardArea.X, Math.Min(targetPos.x, worldStandardArea.X + worldStandardArea.Width));
                float nearestZ = Math.Max(worldStandardArea.Y, Math.Min(targetPos.z, worldStandardArea.Y + worldStandardArea.Height));
                result = new Vector3Logic(nearestX, 0, nearestZ);
            }
            result.y = rectEntityPos.y;
            return result;
        }

        /// <summary>
        /// 将一个xy被当做中心点（center）使用的RectInt转换成世界坐标下标准的（xy为min）的RectInt
        /// </summary>
        /// <param name="worldOffset"></param>
        /// <param name="rect"></param>
        /// <returns></returns>
        private static RectInt CalcWorldStandardRect(float worldXOffset, float worldYOffset, RectInt rect)
        {
            return new RectInt(
                    (int)(worldXOffset + rect.X - rect.Width * 0.5f),
                    (int)(worldYOffset + rect.Y - rect.Height * 0.5f),
                    rect.Width,
                    rect.Height);
        }

        public static bool GetEntitiesByDynCfgKeys(LevelRegion region, LevelEntity triggerEntity, IReadOnlyList<DynCfgKey> dynKeys, List<LevelEntity> entities, bool includeHide = false)
        {
            if (dynKeys == null || dynKeys.Count == 0)
            {
                LogicLog.LogError($"没有配置tagOrMcid，实体mcid：{triggerEntity?.entityConfig.id}");
                return false;
            }
            if (entities == null)
            {
                LogicLog.LogError("参数entities不能为空.");
                return false;
            }
            //HashSet去重
            foreach (var dynKey in dynKeys)
            {
                if (!dynKey.TryGetValue(triggerEntity, out int tagOrMcid))
                {
                    LogicLog.LogError("通过动态参数获取实时参数失败，可能实体上找不到对应的key：" + dynKey.dynamicKey);
                    continue;
                }
                _tempEntityTagOrMcids.Add(tagOrMcid);
            }
            //搜索
            foreach (int tagOrMcid in _tempEntityTagOrMcids)
            {
                if (tagOrMcid == 0)
                {
                    entities.Add(triggerEntity);
                }
                else
                {
                    List<LevelEntity> tempEntities = ListPool<LevelEntity>.Get();
                    region.GetEntitiesByTagOrMcid(tagOrMcid, tempEntities, includeHide);
                    if (tempEntities.Count == 0)
                    {
                        LogicLog.LogError($"根据动态参数获取到的实体tagOrMcid：{tagOrMcid} 没有找到匹配的实体.");
                    }
                    else
                    {
                        foreach (var entity in tempEntities)
                        {
                            entities.Add(entity);
                        }
                    }
                    ListPool<LevelEntity>.Put(tempEntities);
                }
            }
            _tempEntityTagOrMcids.Clear();
            return entities.Count > 0;
        }

        public static bool GetTeleportPos(LevelEntity portal, out Vector3Logic position)
        {
            position = Vector3Logic.zero;
            Vector3Logic teleportPos = portal.position + Vector3Logic.forward * LgLevelConst.TeleportDisFromPortal;
            if (portal.region.terrain.FindNearestPoint(teleportPos, out var realPos))
            {
                position = realPos;
            }
            else
            {
                LogicLog.LogError($"传送门[mcid={portal.entityConfig?.id}, position={portal.position}]指定方向上找不到合法网格点，尝试传送位置：{teleportPos}。");
                return false;
            }
            return true;
        }
    }
}
